<?php

namespace Slowlyo\LaravelResponse;

use Illuminate\Http\Response as HttpResponse;
use Illuminate\Http\Resources\Json\JsonResource;

class JsonResponse
{
    /**
     * @param string $message
     * @param int $code
     * @param null $data
     * @param array $header
     * @param int $options
     *
     * @return  \Illuminate\Http\JsonResponse
     */
    public function fail(string $message = '', int $code = HttpResponse::HTTP_INTERNAL_SERVER_ERROR, $data = null, array $header = [], int $options = JSON_UNESCAPED_UNICODE)
    {
        $status = ($code >= 400 && $code <= 499) ? 'error' : 'fail';

        $message = $message ?: (HttpResponse::$statusTexts[$code] ?? 'Service error');

        return response()->json([
            'error'   => true,
            'status'  => $status,
            'code'    => $code,
            'message' => $message,// 错误描述
            'data'    => (object)$data,// 错误详情
        ], 200, $header, $options);
    }

    public function errorParam($message = 'Param Error', $data = null)
    {
        return $this->fail($message, HttpResponse::HTTP_BAD_REQUEST, $data);
    }

    public function errorPermission($message = 'Permission Error', $data = null)
    {
        return $this->fail($message, HttpResponse::HTTP_FORBIDDEN, $data);
    }

    public function errorBadRequest($message = 'Bad Request', $data = null)
    {
        return $this->fail($message, HttpResponse::HTTP_BAD_REQUEST, $data);
    }

    public function errorForbidden($message = 'Forbidden')
    {
        return $this->fail($message, HttpResponse::HTTP_FORBIDDEN);
    }

    public function errorInternal($message = 'Internal Error')
    {
        return $this->fail($message);
    }

    public function errorUnauthorized($message = 'Unauthorized')
    {
        return $this->fail($message, HttpResponse::HTTP_UNAUTHORIZED);
    }

    public function errorNotFound($message = '404 Not Found')
    {
        return $this->fail($message, HttpResponse::HTTP_NOT_FOUND);
    }

    /**
     * @param JsonResource|array|null $data
     * @param string $message
     * @param array $otherData
     * @param int $code
     * @param array $headers
     * @param int $option
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function success($data = null, string $message = '', array $otherData = [], int $code = HttpResponse::HTTP_OK, array $headers = [], int $option = JSON_UNESCAPED_UNICODE)
    {
        $message = $message ?: (HttpResponse::$statusTexts[$code] ?? 'OK');

        $additionalData = [
            'error'   => false,
            'status'  => 'success',
            'code'    => $code,
            'message' => $message,
        ];

        if ($otherData) {
            $additionalData = array_merge($additionalData, $otherData);
        }

        if ($data instanceof JsonResource) {
            return $data->additional($additionalData)->response();
        }

        if ($data === null) {
            $data = (object)$data;
        }

        return response()->json(array_merge($additionalData, ['data' => $data]), 200, $headers, $option);
    }

    /**
     * @param JsonResource|array|null $data
     * @param string $message
     * @param string $location
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function created($data = null, string $message = 'Created', string $location = '')
    {
        $response = $this->success($data, $message, [], HttpResponse::HTTP_CREATED);
        if ($location) {
            $response->header('Location', $location);
        }

        return $response;
    }

    public function noContent($message = 'No content')
    {
        return $this->success(null, $message, [], HttpResponse::HTTP_NO_CONTENT);
    }

    public function accepted($message = 'Accepted')
    {
        return $this->success(null, $message, [], HttpResponse::HTTP_ACCEPTED);
    }

    public function successMessage($message = 'OK')
    {
        return $this->success([], $message);
    }

    public function autoResponse($flag, $text = '操作', $successMessage = '', $failMessage = '')
    {
        if ($flag) {
            return $this->successMessage($successMessage ?: $text . '成功');
        }

        return $this->fail($failMessage ?: $text . '失败');
    }
}
